#include "stdafx.h"
#include "gp_Ax2.h"
#include "gp.h"
#include "gp_Pnt.h"
#include "gp_Dir.h"
#include "gp_Ax1.h"
#include "gp_Trsf.h"
#include "gp_Vec.h"
#include "gp.h"
#include <cmath>


gp_Ax2::gp_Ax2() : vydir(0.,1.,0.), vxdir(1.,0.,0.)
{ }

gp_Ax2::gp_Ax2(const gp_Pnt& P,
	const gp_Dir& N,
	const gp_Dir& Vx) : axis(P, N), vydir(N), vxdir(N)
{
	vxdir.CrossCross(Vx, N);
	vydir.Cross(vxdir);
}

void gp_Ax2::SetAxis (const gp_Ax1&  A1)
{
	double a =  A1.Direction() * vxdir;
	if(abs(abs(a) - 1.) <= Precision_Angular) {
		if(a > 0.) {
			vxdir = vydir;
			vydir = axis.Direction();
			axis = A1;
		}
		else {
			vxdir = axis.Direction();
			axis = A1;
		}
	}
	else {
		axis = A1;
		vxdir = axis.Direction().CrossCrossed (vxdir, axis.Direction());
		vydir = axis.Direction().Crossed      (vxdir);
	}
}

void gp_Ax2::SetDirection (const gp_Dir&  V)
{ 
	double a =  V * vxdir;
	if(abs(abs(a) - 1.) <= Precision_Angular) {
		if(a > 0.) {
			vxdir = vydir;
			vydir = axis.Direction();
			axis.SetDirection (V);
		}
		else {
			vxdir = axis.Direction();
			axis.SetDirection (V);
		}
	}
	else {
		axis.SetDirection (V);
		vxdir = V.CrossCrossed (vxdir, V);
		vydir = V.Crossed (vxdir);
	}
}

void gp_Ax2::SetLocation (const gp_Pnt& P)
{ axis.SetLocation(P); }

void gp_Ax2::SetXDirection (const gp_Dir&  Vx)
{
	vxdir = axis.Direction().CrossCrossed (Vx, axis.Direction());
	vydir = axis.Direction().Crossed      (vxdir);
}

void gp_Ax2::SetYDirection (const gp_Dir& Vy)
{
	vxdir = Vy.Crossed (axis.Direction());
	vydir = (axis.Direction()).Crossed (vxdir);
}

double gp_Ax2::Angle (const gp_Ax2& Other) const
{ return axis.Angle (Other.axis); }

const gp_Ax1& gp_Ax2::Axis () const
{ return axis; }

const gp_Dir& gp_Ax2::Direction () const
{ return axis.Direction(); }

const gp_Pnt& gp_Ax2::Location () const
{ return axis.Location(); }

const gp_Dir& gp_Ax2::XDirection () const
{ return vxdir; }

const gp_Dir& gp_Ax2::YDirection () const
{ return vydir; }

bool gp_Ax2::IsCoplanar 
	(const gp_Ax2& Other,
	const double LinearTolerance,
	const double AngularTolerance) const
{
	const gp_Dir& DD =       axis.Direction();
	const gp_Pnt& PP =       axis.Location ();
	const gp_Pnt& OP = Other.axis.Location ();
	double D1 = (DD.X() * (OP.X() - PP.X()) + 
		DD.Y() * (OP.Y() - PP.Y()) + 
		DD.Z() * (OP.Z() - PP.Z()));
	if (D1 < 0 ) D1 = - D1;
	return (D1 <= LinearTolerance &&
		axis.IsParallel (Other.axis, AngularTolerance));
}

bool gp_Ax2::IsCoplanar
	(const gp_Ax1& A,
	const double LinearTolerance,
	const double AngularTolerance) const
{
	const gp_Dir& DD = axis.Direction();
	const gp_Pnt& PP = axis.Location ();
	const gp_Pnt& AP = A   .Location ();
	double D1 = (DD.X() * (AP.X() - PP.X()) + 
		DD.Y() * (AP.Y() - PP.Y()) + 
		DD.Z() * (AP.Z() - PP.Z()));
	if (D1 < 0) D1 = - D1;
	return (D1 <= LinearTolerance &&
		axis.IsNormal (A, AngularTolerance));
}

void gp_Ax2::Rotate(const gp_Ax1& A1, const double Ang)
{
	gp_Pnt Temp = axis.Location();
	Temp.Rotate  (A1, Ang);
	axis.SetLocation (Temp);
	vxdir.Rotate (A1, Ang);
	vydir.Rotate (A1, Ang);
	axis.SetDirection (vxdir.Crossed (vydir));
}

gp_Ax2 gp_Ax2::Rotated(const gp_Ax1& A1,
	const double Ang) const
{
	gp_Ax2 Temp = *this;
	Temp.Rotate (A1, Ang);
	return Temp;
} 

void gp_Ax2::Scale (const gp_Pnt& P, const double S)
{
	gp_Pnt Temp = axis.Location();
	Temp.Scale (P, S);
	axis.SetLocation (Temp);
	if (S < 0.0) {
		vxdir.Reverse ();
		vydir.Reverse ();
	}
}

gp_Ax2 gp_Ax2::Scaled(const gp_Pnt& P,
	const double S) const 
{
	gp_Ax2 Temp = *this;
	Temp.Scale (P, S);
	return Temp;
}

void gp_Ax2::Transform (const gp_Trsf& T)
{
	gp_Pnt Temp = axis.Location();
	Temp.Transform (T);
	axis.SetLocation (Temp);
	vxdir.Transform (T);
	vydir.Transform (T);
	axis.SetDirection (vxdir.Crossed (vydir));
}

gp_Ax2 gp_Ax2::Transformed(const gp_Trsf& T) const
{
	gp_Ax2 Temp = *this;
	Temp.Transform (T);
	return Temp;
}

void gp_Ax2::Translate (const gp_Vec& V)
{ axis.Translate (V); }

gp_Ax2 gp_Ax2::Translated(const gp_Vec& V) const
{
	gp_Ax2 Temp = *this;
	Temp.Translate (V);
	return Temp;
}

void gp_Ax2::Translate (const gp_Pnt& P1, const gp_Pnt& P2)
{ axis.Translate (P1, P2); }

gp_Ax2 gp_Ax2::Translated (const gp_Pnt& P1,
	const gp_Pnt& P2)  const
{
	gp_Ax2 Temp = *this;
	Temp.Translate (P1, P2);
	return Temp;
}
gp_Ax2::gp_Ax2 (const gp_Pnt& P, const gp_Dir& V) :
axis(P,V)
{
  double A = V.X();
  double B = V.Y();
  double C = V.Z();
  double Aabs = A;
  if (Aabs < 0) Aabs = - Aabs;
  double Babs = B;
  if (Babs < 0) Babs = - Babs;
  double Cabs = C;
  if (Cabs < 0) Cabs = - Cabs;
  gp_Dir D;
  
  //  pour determiner l axe X :
  //  on dit que le produit scalaire Vx.V = 0. 
  //  et on recherche le max(A,B,C) pour faire la division.
  //  l'une des coordonnees du vecteur est nulle. 
  
  if      ( Babs <= Aabs && Babs <= Cabs) {
    if (Aabs > Cabs) D.SetCoord(-C,0., A);
    else             D.SetCoord( C,0.,-A);
  }
  else if ( Aabs <= Babs && Aabs <= Cabs) {
    if (Babs > Cabs) D.SetCoord(0.,-C, B);
    else             D.SetCoord(0., C,-B);
  }
  else {
    if (Aabs > Babs) D.SetCoord(-B, A,0.);
    else             D.SetCoord( B,-A,0.);
  }
  SetXDirection(D);
}

void gp_Ax2::Mirror (const gp_Pnt& P)
{
  gp_Pnt Temp = axis.Location();
  Temp.Mirror (P);
  axis.SetLocation (Temp);
  vxdir.Reverse ();
  vydir.Reverse ();
}

gp_Ax2 gp_Ax2::Mirrored(const gp_Pnt& P) const
{
  gp_Ax2 Temp = *this;
  Temp.Mirror (P);
  return Temp;
}

void gp_Ax2::Mirror (const gp_Ax1& A1)
{
  vydir.Mirror (A1);
  vxdir.Mirror (A1);
  gp_Pnt Temp = axis.Location();
  Temp.Mirror (A1);
  axis.SetLocation (Temp);
  axis.SetDirection (vxdir.Crossed (vydir));
}

gp_Ax2 gp_Ax2::Mirrored(const gp_Ax1& A1) const
{
  gp_Ax2 Temp = *this;
  Temp.Mirror (A1);
  return Temp;
}

void gp_Ax2::Mirror (const gp_Ax2& A2)
{
  vydir.Mirror (A2);
  vxdir.Mirror (A2);
  gp_Pnt Temp = axis.Location();
  Temp.Mirror (A2);
  axis.SetLocation (Temp);
  axis.SetDirection (vxdir.Crossed (vydir));
}

gp_Ax2 gp_Ax2::Mirrored(const gp_Ax2& A2) const 
{
  gp_Ax2 Temp = *this;
  Temp.Mirror (A2);
  return Temp;
}

